/**
 * 合并参数
 * @param args 需要合并的参数，第一个参数为合并到的目标参数
 * @returns
 */
export default function MergeObjs(...args: any) {
    return merge(true, ...args);
}

//仿JQuery3.4.1版本写的$.extend方法，用来合并json对象
function merge(this: any, ...args: any) {
    let options,
        name,
        src,
        copy,
        copyIsArray,
        clone,
        target = args[0] || {},
        i = 1,
        length = args.length,
        deep = false;

    if (typeof target === "boolean") {
        deep = target;
        target = args[i] || {};
        i++;
    }

    if (typeof target !== "object" && !isFunction(target)) {
        target = {};
    }

    if (i === length) {
        target = this;
        i--;
    }

    for (; i < length; i++) {
        if ((options = args[i]) != null) {
            for (name in options) {
                copy = options[name];

                if (name === "__proto__" || target === copy) {
                    continue;
                }

                if (deep && copy && (isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) {
                    src = target[name];

                    if (copyIsArray && !Array.isArray(src)) {
                        clone = [];
                    } else if (!copyIsArray && !isPlainObject(src)) {
                        clone = {};
                    } else {
                        clone = src;
                    }

                    copyIsArray = false;

                    target[name] = merge(deep, clone, copy);
                } else if (copy !== undefined) {
                    target[name] = copy;
                }
            }
        }
    }

    return target;
}

function isFunction(obj: any) {
    return typeof obj === "function" && typeof obj.nodeType !== "number";
}

function isPlainObject(obj: any) {
    let proto, Ctor;

    let class2type = {};
    let toString = class2type.toString;
    let getProto = Object.getPrototypeOf;
    let hasOwn = class2type.hasOwnProperty;
    let fnToString = hasOwn.toString;
    let ObjectFunctionString = fnToString.call(Object);

    if (!obj || toString.call(obj) !== "[object Object]") {
        return false;
    }

    proto = getProto(obj);

    if (!proto) {
        return true;
    }

    Ctor = hasOwn.call(proto, "constructor") && proto.constructor;
    return typeof Ctor === "function" && fnToString.call(Ctor) === ObjectFunctionString;
}
